#ifndef __P_LEXER_H__
#define __P_LEXER_H__

#include "p_types.h"

#include <vector>
#include <string>

// struct/class forward definitions...
struct p_token_struct;
struct p_position_struct;

// typedef forward definitions...
typedef p_token_struct* p_token_struct_ptr;
typedef std::vector<p_token_struct> p_token_struct_list;
typedef p_token_struct_list* p_token_struct_list_ptr;
typedef p_position_struct* p_position_struct_ptr;

enum p_token_type
{
   TOK_IGNORE, // is used for comments and other tokens to be ignored.
   TOK_ADD,
   TOK_SUB,
   TOK_SUB_SUB,
   TOK_DIV,
   TOK_MUL,
   TOK_POINT,
   TOK_SEMICOLON,
   TOK_DPOINT,
   TOK_ADDR,
   TOK_EQ,
   TOK_ASSIGN,
   TOK_LE,
   TOK_NE,
   TOK_LT,
   TOK_GE,
   TOK_GT,
   TOK_IDENT,
   TOK_VAR,
   TOK_BEGIN,
   TOK_END,
   TOK_STRING,
   TOK_TEMPLATE,
   TOK_RBRO,
   TOK_RBRC,
   TOK_EBRO,
   TOK_EBRC,
   TOK_CBRO,
   TOK_CBRC,
   TOK_VBAR,
   TOK_COLON,
   TOK_PROGRAM,
   TOK_SIGNED,
   TOK_UNSIGNED,
   TOK_BYTE,
   TOK_WORD,
   TOK_DWORD,
   TOK_TBYTE,
   TOK_RECORD,

   TOK_READ_ONLY,
   TOK_PRECONDITION,
   TOK_POSTCONDITION,
   TOK_EXPRESSION,

   TOK_AND,
   TOK_NAND,
   TOK_OR,
   TOK_NOR,
   TOK_XOR,

   TOK_POWER,
   TOK_EXCLAMATION_MARK,

   TOK_FUNCTION,
   TOK_PROTO,
   TOK_ATTRIBUTES,
   TOK_PASCAL,
   TOK_NAKED,
   TOK_CDECL,
   TOK_STDCALL,
   TOK_DLLIMPORT,
   TOK_EXTERN,

   TOK_NIL,

   TOK_EOF
};

/**
 * This function converts a token_type into a string.
 *
 * @param token_type The enum type for the token structure.
 */
std::string token_type_to_string(const p_token_type &token_type);

/**
 * This is the position structure for the lexer/compiler. This structure
 * represents a position within a given text.
 *
 * @brief Represents a position within a text.
 */
struct p_position_struct
{
   p_unsigned_int index;
   p_unsigned_int line;
   p_unsigned_int col;
};

/**
 * This function creates a new position struct.
 *
 * @param index The text file absolute index within a file.
 * @param line The line marker within a file.
 * @param col The current column within the text file.
 */
p_position_struct position_struct_create(const p_unsigned_int &index = 0,
                                         const p_unsigned_int &line = 0,
                                         const p_unsigned_int &col = 0);

/**
 * This is just another constructor for a position struct.
 *
 * @param pos This position is being copied.
 * @return A new instance of the position_struct which is a copy of the given one.
 */
p_position_struct position_struct_create(const p_position_struct &pos);

/**
 * This function returns a string representation of a position struct.
 *
 * @param pos The position which is converted into a std::string.
 */
std::string position_struct_to_string(const p_position_struct &pos);

/**
 * This structure defines all the necessary information needed for a single
 * lexer token for the p programming language.
 *
 * @brief The token structure for the compiler.
 */
struct p_token_struct
{
   p_token_type type;
   std::string ident;
   p_position_struct pos;
};

/**
 * Constructor function for a p_token_struct. The token returned is the EOF token.
 */
p_token_struct token_struct_create();

/**
 * Constructor function for a p_token_struct.
 *
 * @param type The type identifier for the current token structure.
 * @param index The absolute index within the file.
 * @param line The line number for the token structure starting from 0.
 * @param col The column index for the token structure starting from 0.
 */
p_token_struct token_struct_create(const p_token_type &type,
                                   const p_unsigned_int &index = 0,
                                   const p_unsigned_int &line = 0,
                                   const p_unsigned_int &col = 0);

/**
 * Constructor function for a p_token_struct.
 *
 * @param type The type identifier for the current token structure.
 * @param pos The line number for the token structure starting from 0.
 */
p_token_struct token_struct_create(const p_token_type &type,
                                   const p_position_struct &pos);

/**
 * Constructor function for a p_token_struct.
 *
 * @param type The type identifier for the current token structure.
 * @param ident The identifier for the token.
 * @param pos The line number for the token structure starting from 0.
 */
p_token_struct token_struct_create(const p_token_type &type,
                                   const std::string &ident,
                                   const p_position_struct &pos);

/**
 * This is the copy-constructor for token_structs.
 */
p_token_struct token_struct_create(const p_token_struct &token_struct);

/**
 * This function is just used for converting a token structure into a std string.
 * Primarily used for debugging purposes.
 *
 * @param token The token structure which is converted into a string.
 */
std::string token_struct_to_string(const p_token_struct &token);

/**
 * This function clones a token_struct; just like a copy constructor.
 *
 * @param token_struct The token_struct which is going to be copied.
 * @return A new token_struct which is an exact copy of the given one.
 */
p_token_struct token_struct_clone(const p_token_struct &token_struct);

/**
 * This function converts a list of tokens into a string representing all tokens
 * read sofar.
 *
 * @param token_list This is a pointer to a const token list.
 */
std::string
token_struct_list_to_string(const p_token_struct_list_ptr token_list);

/**
 * This function generates a list of tokens which represents the given input file.
 * The whole file will be in memory and all manipulations will be performed in memory as well.
 *
 * @param file_content This parameter contains the whole family.
 * @return A list of p_token_struct which is used to represent the whole file.
 */
p_token_struct_list_ptr tokenize(const std::string &file_content);

#endif
